package com.novel.framework.satoken.service.impl;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.novel.common.constants.DeviceType;
import com.novel.common.exception.business.BusinessException;
import com.novel.framework.factory.AsyncFactory;
import com.novel.framework.satoken.LoginHelper;
import com.novel.framework.satoken.service.SysLoginService;
import com.novel.framework.utils.AddressUtils;
import com.novel.framework.utils.servlet.IpUtils;
import com.novel.framework.utils.servlet.ServletUtils;
import com.novel.captcha.adapter.Captcha;
import com.novel.captcha.exception.CaptchaIncorrectException;
import com.novel.system.domain.LoginUser;
import com.novel.system.domain.SysUser;
import com.novel.system.service.SysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * 登录服务
 *
 * @author novel
 * @since 2023/1/10 18:39
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysLoginServiceImpl implements SysLoginService {

    private final SysUserService sysUserService;
    private final Captcha captcha;
    private final AsyncFactory asyncFactory;

    @Override
    public String login(String username, String password, String code, String key, boolean rememberMe) {
        if (!captcha.validate(key, code)) {
            throw new CaptchaIncorrectException("验证码不正确");
        }
        SysUser sysUser = loadUserByUsername(username);
        if (!BCrypt.checkpw(password, sysUser.getPassword())) {
            throw new BusinessException("用户密码错误");
        }

        // 此处可根据登录用户的数据不同 自行创建 loginUser
        LoginUser loginUser = buildLoginUser(sysUser);
        LoginHelper.loginByDevice(loginUser, DeviceType.PC);

        //记录登录信息
        asyncFactory.recordLogininfor(loginUser);
        //更新用户登录信息
        asyncFactory.updateLoginUser(loginUser);
        return StpUtil.getTokenValue();
    }

    private LoginUser buildLoginUser(SysUser user) {
        LoginUser loginUser = new LoginUser();
        loginUser.setUser(user);
        setUserAgent(loginUser);
        return loginUser;
    }


    /**
     * 设置用户代理信息
     *
     * @param loginUser 登录信息
     */
    private void setUserAgent(LoginUser loginUser) {
        final UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
        String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
        loginUser.setIpaddr(ip);
        loginUser.getUser().setLoginIp(ip);
        loginUser.getUser().setLoginDate(new Date());
        loginUser.setLoginLocation(AddressUtils.getRealAddress(ip));
        loginUser.setBrowser(userAgent.getBrowser().getName());
        loginUser.setOs(userAgent.getOs().toString());
    }

    @Override
    public void logout() {
        try {
            StpUtil.logout();
        } catch (NotLoginException ignored) {
        }
    }


    private SysUser loadUserByUsername(String username) {
        SysUser user = sysUserService.findUserByUserName(username);
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户：{} 不存在.", username);
            throw new BusinessException("登录用户：" + username + " 不存在");
        } else if ("1".equals(user.getDelFlag())) {
            log.info("登录用户：{} 已被删除.", username);
            throw new BusinessException("登录用户：" + username + " 已被删除");
        } else if ("1".equals(user.getStatus())) {
            log.info("登录用户：{} 已被停用.", username);
            throw new BusinessException("登录用户：" + username + " 已被停用");
        }
        return user;
    }
}
